package com.cskaoyan.mall.user.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.cskaoyan.mall.common.util.DateUtil;
import com.cskaoyan.mall.common.util.MD5;
import com.cskaoyan.mall.user.consts.UserConstants;
import com.cskaoyan.mall.user.dto.UserLoginDTO;
import com.cskaoyan.mall.user.dto.UserLoginInfoDTO;
import com.cskaoyan.mall.user.mapper.UserInfoMapper;
import com.cskaoyan.mall.user.model.UserInfo;
import com.cskaoyan.mall.user.query.UserInfoParam;
import com.cskaoyan.mall.user.service.UserService;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import java.util.concurrent.TimeUnit;

/**
 * @Author Pudding
 * @Date 2024/7/13 19:26
 */
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserInfoMapper userInfoMapper;
    @Autowired
    RedissonClient redissonClient;

    /**
     * 1. 用户登录的接口实现
     * 分析: 在登录接口中，业务逻辑是什么呢？
     *  a) 根据用户名和密码，查询数据库
     *  b) 如果没有查到，那么说明用户名和密码错误，返回登录失败
     *  c) 如果查到了，说明用户名和密码正确
     *      // 创建token
     *      // 把令牌token和用户信息 保存到Redis
     *  d) 返回令牌
     */
    @Override
    public UserLoginDTO login(UserInfoParam userInfoParam, String ip, String token) {

        //1. 获取用户名和MD5加密之后的密码
        String loginName = userInfoParam.getLoginName();
        String passwd = userInfoParam.getPasswd();
        //使用了DigestUtils类中的md5DigestAsHex方法来生成一个字符串passwd的MD5散列值，并将其转换为十六进制格式的字符串
        String passwdHash = DigestUtils.md5DigestAsHex(passwd.getBytes());

        //2. 根据用户名和加密之后的密码查询数据库
        LambdaQueryWrapper<UserInfo> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(UserInfo::getLoginName,loginName);
        lambdaQueryWrapper.eq(UserInfo::getPasswd,passwdHash);
        UserInfo userInfo = userInfoMapper.selectOne(lambdaQueryWrapper);

        //3. 如果没有查到，那么说明用户名和密码错误，返回登录失败
        if (userInfo == null){
            return null;
        }

        //4. 如果查到了，说明用户名和密码正确
        //4.1 把令牌token和用户信息 保存到Redis
        //redis中的key作为user:login+token，value作为userInfo
        String key = UserConstants.USER_LOGIN_KEY_PREFIX + token;
        RBucket<Object> bucket = redissonClient.getBucket(key);
        //把userInfo对象作为value存放进去，可以设置一个登录自动过期的时间 (常用的是2小时)
        bucket.set(new UserLoginInfoDTO(userInfo.getId().toString(), ip), 2, TimeUnit.HOURS);

        //5. 返回令牌对象
        return new UserLoginDTO(userInfo.getNickName(), token);
    }
}
